//
//  OPBoard.m
//  OPFramework
//
//  Created by malcom on 7/12/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "OPBoard.h"
#import "OPCostants.h"
#import "OPTopic.h"

@implementation OPBoard

@synthesize obj_boardConfig;
@synthesize obj_boardRootPath;
@synthesize obj_boardStructure;
@synthesize obj_membersCache;
@synthesize _config_workAsAsync;
@synthesize _config_cacheValidTime;
@synthesize obj_authUser;

- (id) initBoardAndLoadAsync:(BOOL) _asyncLoading address:(NSString *) _addr withAuth:(OPAuthUser *) _auth withDelegate:(NSObject <OPBoard_AsyncResponse> *) _delegate {
	if (_asyncLoading)
		return [[OPBoard alloc] _initAsyncWithBoardAddress: _addr withAuth:_auth withDelegate:_delegate];
	else
		return [[OPBoard alloc] _initWithBoardAddress: _addr withAuth: _auth withDelegate: _delegate];
}

- (id) _initAsyncWithBoardAddress:(NSString *) _url withAuth:(OPAuthUser *) _auth withDelegate:(NSObject <OPBoard_AsyncResponse> *) _delegate {
	self = [super init];
	if (self != nil) {
		_boardDelegate = [_delegate retain];
		_asyncModeActive = YES;
		_config_workAsAsync = YES;
		
		// if the forum itself it's not compatible we return an empty class
		if ( (obj_urlToOFAPILib = [[self _checkOFAPICompatibility: _url] retain]) == nil) {
			[_boardDelegate opboard_init_boardNotSupported: _url];
			return self;
		}
		
		// check for login (if _auth is nil we will remain as anonymous user)
		if (_auth != nil) {
			obj_authUser = [_auth retain];
			obj_authUser._delegateBoard = [self retain];
			[self _testLoginToBoard: _auth]; // perform request
		}
		
		// load configuration
		obj_boardConfig = [[OPBoardConfig alloc] initWithBoard: self];
		[obj_boardConfig addObjectAsListenerForMe: self];
		
		// init members list cache
		obj_membersCache = [[OPMembersCache alloc] initForBoard: self];
		
		// try to load board structure
		obj_boardStructure = [[OPBoardStructure alloc] initWithBoard: self];
		[obj_boardStructure addObjectAsListenerForMe: self];
	}	
	return self;
}

- (id) _initWithBoardAddress:(NSString *) _url withAuth:(OPAuthUser *) _auth withDelegate:(NSObject <OPBoard_AsyncResponse> *) _delegate {
	self = [super initWithBoard: self];
	if (self != nil) {
		_boardDelegate = [_delegate retain];
		_asyncModeActive = NO;
		_config_cacheValidTime = 300; // 6 minutes of cache it's the standard time
		_config_workAsAsync = NO;
		
		// if the forum itself it's not compatible we return an empty class
		if ( (obj_urlToOFAPILib = [[self _checkOFAPICompatibility: _url] retain]) == nil)
			[_boardDelegate opboard_init_boardNotSupported: _url];
		
		// check for login (if _auth is nil we will remain as anonymous user)
		obj_authUser = [_auth retain];
		obj_authUser._delegateBoard = [self retain];
		
		if ([self _testLoginToBoard: _auth])
			[obj_authUser reloadAuthPersonalDatabase]; // refresh personal informations (private messages...)
		
		// try to load board configuration
		[_boardDelegate opboard_init_configurationLoaded: !((obj_boardConfig = [[OPBoardConfig alloc] initWithBoard: self]) == nil)
												forBoard: self];
		
		// try to load board structure
		[_boardDelegate opboard_init_structureLoaded: !((obj_boardStructure = [[OPBoardStructure alloc] initWithBoard: self]) == nil)
											forBoard: self];
		
		// init members list cache
		obj_membersCache = [[OPMembersCache alloc] initForBoard: self];
		
		NSLog(@"Board '%@' successully loaded...",[obj_boardConfig getPropertyForKey: OPBoardConfig_Sitename]);
		
		[_boardDelegate opboard_init_boardReady: YES forBoard:self];

	}
	return self;
}

- (NSURL *) _checkOFAPICompatibility:(NSString *) _rootPathAddress {
	NSURL *_ofapiLibraryAddress = nil;
	if (_ofapiLibraryAddress == nil)
		_ofapiLibraryAddress = [[NSURL URLWithString: [NSString stringWithFormat:@"%@/%@", _rootPathAddress,@"ofapi/ofapi.php"]] retain];
	
	NSError *_lastForumError = nil;
	// try to get some data... if an error will occur probability the forum it's not compatible
	NSString *str = [[NSString alloc] 
					 initWithContentsOfURL: _ofapiLibraryAddress 
					 encoding:NSISOLatin1StringEncoding 
					 error:&_lastForumError];
	
	BOOL ofapiPresent = !(_lastForumError != nil || str == nil); 
	NSLog(@"Checking for OFAPI module on board at %@... %@",_rootPathAddress,(ofapiPresent ? @"OK" : @"FAILED!"));
	if (!ofapiPresent) return nil; else {
		obj_boardRootPath = [_rootPathAddress retain];
		return [_ofapiLibraryAddress autorelease];
	}
}

// async response
- (void)connection: (XMLRPCConnection *)connection didReceiveResponse:(XMLRPCResponse *)response forMethod: (NSString *)method {
	// super class check if it's an error, a numeric response or simply some data to parse
	
	// this is a response for login test
	if ([method isEqualToString: @"logging.login"])
		[self _checkLoginResult: [NSArray arrayWithObjects: response,method,nil]];
	
}

- (void) _checkLoginResult:(NSArray *) _result {
	NSNumber *_code = (NSNumber *)[_result objectAtIndex: 0];
	// login done?
	if ([_code intValue] == OFAPI_LOGIN_SUCCESS) {
		[obj_authUser reloadAuthPersonalDatabase]; // refresh personal informations (private messages...)
	} else {
		[obj_authUser release]; obj_authUser = nil;
	}
	// send result to delegate
	[_boardDelegate opboard_init_loginResult: [_code intValue]  forBoard: self];
}

- (void) dataUpdatedFor:(OPBaseObject *) _obj atMethod:(NSString *) _method {
	// board configuration loaded correctly
	if (_obj == obj_boardConfig) [_boardDelegate opboard_init_configurationLoaded: YES forBoard: self];

	// board structure loaded corretly
	if (_obj == obj_boardStructure) {
		[_boardDelegate opboard_init_structureLoaded: YES forBoard: self];
		[_boardDelegate opboard_init_boardReady: YES forBoard: self];
	}
}

- (void) errorReceivedForDataUpdate:(NSNumber *) _errorCode from:(OPBaseObject *) _obj {
	// board configuration not loaded
	if (_obj == obj_boardConfig) [_boardDelegate opboard_init_configurationLoaded: NO forBoard: self];

	// board structure loaded corretly
	if (_obj == obj_boardStructure) [_boardDelegate opboard_init_structureLoaded: NO forBoard: self];

	[_boardDelegate opboard_init_boardReady: NO forBoard: self];
}

- (void) serverErrorForDataUpdateFrom:(OPBaseObject *) _obj error:(NSDictionary *) _dict {
	// board configuration not loaded
	if (_obj == obj_boardConfig) [_boardDelegate opboard_init_configurationLoaded: NO forBoard: self];

	// board structure loaded corretly
	if (_obj == obj_boardStructure) [_boardDelegate opboard_init_structureLoaded: NO forBoard: self];

	[_boardDelegate opboard_init_boardReady: NO forBoard: self];

}



- (BOOL) _isNumericResponseFromServerAnErrorCode:(NSNumber *) _code forMethod:(NSString *) method {
	return NO;
}

- (BOOL) _testLoginToBoard:(OPAuthUser *) _user {
	// okay you have not specified any auth data, you still logged as anonymous user
	if (_user == nil) return YES;
	
	NSArray *_params = [NSArray arrayWithObjects: 
						_user.user_username,
						_user.user_password,nil];
	[self sendXMLRequestForMethod: @"logging.login"  withParams:_params parseSelector:@selector(_checkLoginResult:)];
	return obj_authUser != nil;
	// mmm some data, we will try to logging in
	/*XMLRPCResponse *_authResp = [self _executeRequestMethodNamed: @"logging.login" 
												 withParams: [NSArray arrayWithObjects: 
															  _user.user_username,
															  _user.user_password,
															  [NSNumber numberWithBool: YES],
															  [NSNumber numberWithBool: YES],
															  nil]];
	// check for response
	int _authRespCode = [[_authResp responseObject] intValue];
	BOOL loggedIn = NO;
	if ((loggedIn = (_authRespCode == OFAPI_LOGIN_SUCCESS)) && ![_authResp isFault]) {
		// if we are logged we will get info about currently logged user profile
		[_user loadData];
		return YES;
	} else return NO;*/
}


- (XMLRPCResponse *) _executeRequestMethodNamed:(NSString *) _method withParams:(NSArray *) _params {
	return [self _executeRequestMethodNamed: _method withParams: _params attachAuthData: nil asyncResponse: nil];
}

- (XMLRPCResponse *) _executeRequestMethodNamed:(NSString *) _method withParams:(NSArray *) _params attachAuthData:(NSArray *) _auth {
	return [self _executeRequestMethodNamed: _method withParams: _params attachAuthData: _auth asyncResponse: nil];
}

- (XMLRPCResponse *) _executeRequestMethodNamed:(NSString *) _method withParams:(NSArray *) _params attachAuthData:(NSArray *) _auth asyncResponse:(id <XMLRPC_AsyncResponse>) _asResp {
    XMLRPCRequest *request = [[[XMLRPCRequest alloc] initWithHost: obj_urlToOFAPILib] retain];
	
	NSMutableDictionary *dataBlock = [[NSMutableDictionary alloc] init];
	
	if (_auth == nil) {
		// add auth block of data (required for some methods)
		if ([obj_authUser isLogged] && [_method isEqualToString: @"logging.login"] == NO) {
			[dataBlock setObject: [NSArray arrayWithObjects: obj_authUser.user_username,obj_authUser.user_password,nil]
						  forKey:@"auth"];
		}
	} else {
		[dataBlock setObject: _auth forKey:@"auth"];
	}
	
	if (_params != nil) [dataBlock setObject: _params forKey:@"data"];
	else [dataBlock setObject: [NSArray array] forKey:@"data"];
	
    [request setMethod: _method withParameters: [NSArray arrayWithObject: dataBlock]];
//NSLog(@"--> called %@ with %d p",_method,[dataBlock count]);
	
	[dataBlock release];
    [request setUserAgent: @"ofapi_objc"];
	
	if (_asResp == nil) {
		// synch request
		XMLRPCResponse *response = [[XMLRPCConnection sendSynchronousXMLRPCRequest: request] retain];
		[request release];
		return [response autorelease];
	} else {
		XMLRPCConnection *connection = [[XMLRPCConnection alloc]
											initWithXMLRPCRequest: request delegate: _asResp];
		if (connection == nil) NSLog(@"error");
		return nil;
	}
}

- (void) _executeAsyncMethodNamed:(NSString *) _named withParams:(NSArray *) _params attachAuthData:(NSArray*) _auth responseObject:(id <XMLRPC_AsyncResponse>) _resp {
	[self _executeRequestMethodNamed: _named withParams: _params attachAuthData: _auth asyncResponse: _resp];
}

- (void) _executeAsyncMethodNamed:(NSString *) _named withParams:(NSArray *) _params responseObject:(id <XMLRPC_AsyncResponse>) _resp {
	[self _executeRequestMethodNamed: _named withParams: _params attachAuthData: nil asyncResponse: _resp];
}

- (OPPost *) getPostWithID:(NSNumber *) _uid forceLoad:(BOOL) _load {
	OPPost *post = nil;
	// search inside cached items
	for (OPForum *cForum in [obj_boardStructure getFlatNormalForumsList]) {
		NSArray *topicsList = [[cForum._forumPages getFlatElements] retain];
		for (OPTopic *cTopic in topicsList)
			post = [cTopic getPostWithID: _uid forceLoad: YES];
		[topicsList release];
	}
	
	// if not found and we want it, ofapi will make an xml request
	if (_load && post == nil)
		post = [[OPPost alloc] initLoadingPostWithID: _uid fromBoard:self];
	return post;
}

- (void) dealloc {
	[obj_authUser release];
	[obj_boardConfig release];
	[obj_boardStructure release];
	[obj_urlToOFAPILib release];
	[obj_boardRootPath release];
	[obj_membersCache release];
	
	[super dealloc];
}

- (void)encodeWithCoder:(NSCoder *)encoder {
	[encoder encodeObject: obj_authUser];
	[encoder encodeObject: obj_boardConfig];
	[encoder encodeObject: obj_boardStructure];
	[encoder encodeObject: obj_urlToOFAPILib];
	[encoder encodeObject: obj_boardRootPath];
	[encoder encodeObject: obj_membersCache];
}

- (id)initWithCoder:(NSCoder *)decoder {
	if (self = [super init]) {
		obj_authUser = [[decoder decodeObject] retain];
		obj_boardConfig = [[decoder decodeObject] retain];
		obj_boardStructure = [[decoder decodeObject] retain];
		obj_urlToOFAPILib = [[decoder decodeObject] retain];
		obj_boardRootPath = [[decoder decodeObject] retain];
		obj_membersCache = [[decoder decodeObject] retain];
	}
	return self;
}

@end
